package top.jacktgq.sxt.bio.ChatRoom.version6;

import top.jacktgq.sxt.bio.ChatRoom.version6.utils.ResourceUtils;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author CandyWall
 * @Date 2019/10/22--18:45
 * @Description 在线聊天室：服务器
 *              目标：加入容器实现群聊
 */
public class ChatServer {
    //新建一个容器用于保存所有Channel的引用，这里不使用普通的List，比如ArrayList，因为ArrayList线程不安全。
    //CopyOnWriteArrayList是线程安全的
    private static CopyOnWriteArrayList<Channel> channelList = new CopyOnWriteArrayList<Channel> ();

    public static void main(String[] args) throws IOException {
        System.out.println("服务器启动...");
        //1、指定端口 使用ServerSocket创建服务器
        ServerSocket serverSocket = new ServerSocket(8888);
        Boolean isUsedForMultiClients = true;   //是否服务于多个客户端
        while (isUsedForMultiClients) {
            //2、阻塞式等待连接accept
            Socket server = serverSocket.accept();
            System.out.println("一个客户端建立了连接");
            Channel channel = new Channel(server);
            channelList.add(channel);//保存channel的引用
            new Thread(channel).start();
        }
        serverSocket.close();
    }

    //一个客户端代表一个Channel
    static class Channel implements Runnable {
        private DataInputStream dis = null;
        private DataOutputStream dos = null;
        private Socket server;
        private String username;
        private boolean isRunning;

        public Channel(Socket server) {

            this.server = server;
            try {
                dis = new DataInputStream(server.getInputStream());
                dos = new DataOutputStream(server.getOutputStream());
                //在创建 接收客户端信息的线程启动之前先获取用户名
                username = dis.readUTF();
                isRunning = true;
            } catch (IOException e) {
                e.printStackTrace();
                //只要在获取连接的过程中发生异常，就释放资源，断开连接
                release();
            }
        }

        //接收消息
        private String receive() {
            String msg = null;
            try {
                msg = dis.readUTF();
            } catch (IOException e) {
                e.printStackTrace();
                release();
            }
            return msg;
        }

        //发送消息
        private void send(String msg) {
            try {
                dos.writeUTF(msg);
                dos.flush();
            } catch (IOException e) {
                e.printStackTrace();
                release();
            }
        }

        //群聊：就是把这个客户端发来的数据转发给其他的客户端
        private void sendOthers(String msg) {
            for (Channel other : channelList) {
                if (other != this) {    //消息不转发给自己自己
                    other.send(msg);
                }
            }
        }

        //释放资源
        private void release() {
            //停止本次与客户端的通信（接收消息和发送消息）
            this.isRunning = false;
            ResourceUtils.close(dis, dos, server);
        }

        @Override
        public void run() {
            while (isRunning) {
                //3、接收客户端发送的消息
                String msg = username + " 对所有人说：" + receive();
                //过滤掉客户端发来的空消息
                if (!"".equals(msg)) {
                    System.out.println(msg);
                    //4、返回消息
                    //send(msg);
                    sendOthers(msg);
                }
            }

            //释放资源
            release();
        }
    }

}
